package org.summerframework.component.upload.config;

import com.aliyun.oss.OSSClient;
import org.summerframework.component.upload.DefaultUploadServerServiceImpl;
import org.summerframework.component.upload.FileUploadServerService;
import org.summerframework.component.upload.FileUploadService;
import org.summerframework.component.upload.converter.MultipartFileConverter;
import org.summerframework.component.upload.fastdfs.FastDFSTemplateFactory;
import org.summerframework.component.upload.fastdfs.FastDFSUploadServerServiceImpl;
import org.summerframework.component.upload.fastdfs.FastdfsTemplate;
import org.summerframework.component.upload.fastdfs.FastdfsTemplateImpl;
import org.summerframework.component.upload.ftp.FtpProperties;
import org.summerframework.component.upload.ftp.FtpUploadServerServiceImpl;
import org.summerframework.component.upload.oss.OSSUploadServerServiceImpl;
import org.summerframework.component.upload.smb.SmbProperties;
import org.summerframework.component.upload.smb.SmbUploadServerServiceImpl;
import org.summerframework.component.upload.util.UploadFileUtil;
import org.summerframework.core.base.result.DefaultResultCode;
import org.summerframework.core.exception.WebException;
import org.summerframework.core.util.SpringContextUtil;
import jcifs.smb.SmbFile;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.csource.fastdfs.ClientGlobal;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import sun.net.ftp.FtpClient;

import javax.annotation.Resource;
import java.time.Duration;

/**
 * @author 石超
 * @version v1.0.0
 */
@Configuration
@ComponentScan({"org.summerframework.component.upload"})
@MapperScan("org.summerframework.component.upload.*.model")
@EnableWebMvc
@EnableConfigurationProperties({UploadConfiguration.UploadProperties.class, UploadConfiguration.File.class})
public class UploadConfiguration implements WebMvcConfigurer {

    @Resource
    private SpringContextUtil springContextUtil;

    @Resource
    private UploadProperties uploadProperties;

    @Resource
    private FileUploadService fileUploadService;

    @Bean
    public UploadFileUtil uploadFileUtil() {
        return new UploadFileUtil(uploadProperties.ffmpegPath, uploadProperties.videoThumbSize,
                uploadProperties.simpleCover);
    }

    @Bean
    public MultipartFileConverter multipartFileToLongConverter() {
        return new MultipartFileConverter(fileUploadService);
    }

    @Bean
    @ConditionalOnMissingBean(FileUploadServerService.class)
    public DefaultUploadServerServiceImpl defaultUploadServerService(File file) {
        if (StringUtils.isBlank(file.getPath())) {
            throw new WebException(DefaultResultCode.SYSTEM_ERROR, "spring.upload.file.path not null");
        }

        return new DefaultUploadServerServiceImpl(file.getPath());
    }

    @Configuration
    @ConditionalOnClass(ClientGlobal.class)
    @ConditionalOnProperty(name = "spring.upload.type", havingValue = "fastDFS")
    static class FastDFSConfiguration {

        @Bean
        @ConfigurationProperties("spring.upload.fastdfs")
        public FastDFSTemplateFactory fastDFSTemplateFactory() {
            return new FastDFSTemplateFactory();
        }

        @Bean
        public FastDFSUploadServerServiceImpl fastDFSUploadServerService() {
            return new FastDFSUploadServerServiceImpl();
        }

        @Bean
        public FastdfsTemplate fdfsBaseService() {
            return new FastdfsTemplateImpl(fastDFSTemplateFactory());
        }
    }

    @Configuration
    @ConditionalOnClass(OSSClient.class)
    @ConditionalOnProperty(name = "spring.upload.type", havingValue = "oss")
    @AutoConfigureBefore(UploadConfiguration.class)
    @EnableConfigurationProperties(OSS.class)
    static class OSSConfiguration {
        @Bean
        public OSSUploadServerServiceImpl ossUploadServerService(OSS oss) {
            return new OSSUploadServerServiceImpl(oss);
        }
    }

    @Configuration
    @ConditionalOnMissingBean(FtpClient.class)
    @AutoConfigureBefore(UploadConfiguration.class)
    @EnableConfigurationProperties(FtpProperties.class)
    @ConditionalOnProperty(name = "spring.upload.type", havingValue = "ftp")
    static class FtpConfiguration {

        @Bean
        public FtpUploadServerServiceImpl ftpUploadServerService(FtpProperties properties) {
            return new FtpUploadServerServiceImpl(properties);
        }
    }

    @Configuration
    @ConditionalOnMissingBean(SmbFile.class)
    @AutoConfigureBefore(UploadConfiguration.class)
    @EnableConfigurationProperties(SmbProperties.class)
    @ConditionalOnProperty(name = "spring.upload.type", havingValue = "smb")
    static class SmbConfiguration {

        @Bean
        public SmbUploadServerServiceImpl smbUploadServerService(SmbProperties properties) {
            return new SmbUploadServerServiceImpl(properties);
        }
    }

    @Getter
    @Setter
    @ConfigurationProperties(prefix = "spring.upload")
    public static class UploadProperties {

        private String type = "file";

//        /**
//         * width x height
//         * sq: 100x100
//         * separated 'x'
//         */
//        private String ratio = "200x200";
//
//        /**
//         * default compression
//         */
//        private boolean defaultCompression = true;

        private String ffmpegPath;

        private String videoThumbSize;

        private boolean simpleCover;
    }

    @Getter
    @Setter
    @ConfigurationProperties("spring.upload.file")
    public static class File {
        /**
         * file path.
         */
        private String path;
    }

    @Getter
    @Setter
    @ConfigurationProperties("spring.upload.oss")
    public static class OSS {
        private String domain;
        private String endpoint;
        private String accessKeyId;
        private String secret;
        private String bucketName;
        private boolean encrypt = true;
        private boolean ossUrl = true;
        private Duration expirationTime = Duration.ofMinutes(60);

        /**
         * auto create bucket.
         */
        private boolean auto = false;
    }
}
